import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

public class NIOClient extends Thread {

	public static final int NumberOfClients = 1;
	public static final int NumberOfMessages = 1;
	public static final int BUF_SIZE = 20;
	public static boolean running = true;

	private String serverIP;
	private int serverPort;
	ByteBuffer buf;
	private Selector selector;
	private SocketChannel socketChannel;

	public NIOClient(String serverIP, int serverPort) {
		this.serverIP = serverIP;
		this.serverPort = serverPort;
	}

	public void setBuffer(ByteBuffer buf, String command) {

		byte[] comm = command.getBytes();

		int i = 0;
		while (buf.hasRemaining()) {
			if (i < comm.length) {
				buf.put((byte) comm[i]);
			} else {
				buf.put((byte) 0);
			}
			i++;
		}

		buf.flip();
	}

	@Override
	public void run() {

		try {

			buf = ByteBuffer.allocateDirect(BUF_SIZE);
			//
			setBuffer(buf, "Hello from client");

			selector = Selector.open();
			socketChannel = SocketChannel.open();
			socketChannel.configureBlocking(false);
			socketChannel.connect(new InetSocketAddress(this.serverIP,
					this.serverPort));
			socketChannel.register(selector, SelectionKey.OP_CONNECT, buf);

			while (running) {

				selector.select();

				for (Iterator<SelectionKey> it = selector.selectedKeys()
						.iterator(); it.hasNext();) {
					SelectionKey key = it.next();
					it.remove();

					if (key.isConnectable()) {
						connect(key);
					} else if (key.isWritable()) {
						write(key);
					} else if (key.isReadable()) {
						read(key);
					}
				}
			}

		} catch (IOException e) {
			System.out.println("IOEXCEPTION");
			e.printStackTrace();

		} finally {
			if (selector != null) {
				try {
					selector.close();
				} catch (IOException e) {
					System.out.println("SELECTOR CLOSE");
					e.printStackTrace();
				}
			}

			if (socketChannel != null) {
				try {
					socketChannel.close();
				} catch (IOException e) {
					System.out.println("SOCKETCHANNEL");
					e.printStackTrace();
				}
			}
		}
	}

	public void connect(SelectionKey key) throws IOException {
		System.out.println("CONNECT");

		SocketChannel socketChannel = (SocketChannel) key.channel();
		if (!socketChannel.finishConnect()) {
			System.err.println("Eroare finishConnect");
			running = false;
		}

		// socketChannel.close();
		key.interestOps(SelectionKey.OP_WRITE);
	}

	public void write(SelectionKey key) throws IOException {
		System.out.println("WRITE");
		Charset charset = Charset.forName("ISO-8859-1");
		CharBuffer c = CharBuffer.wrap("Hello from client!");
		ByteBuffer b = charset.encode(c);
		SocketChannel socketChannel = (SocketChannel) key.channel();
		socketChannel.write(b);
		key.interestOps(SelectionKey.OP_READ);
	}

	public void read(SelectionKey key) throws IOException {
		System.out.println("READ: ");
		ByteBuffer buffer = ByteBuffer.allocate(20);
		int bytesRead = 0;
		SocketChannel socketChannel = (SocketChannel) key.channel();
		if ((bytesRead = socketChannel.read(buffer)) > 0) {
            buffer.flip();
            System.out.println("Clientul a citit: " + Charset.defaultCharset().decode(
                    buffer));
            buffer.clear();
        }
        if (bytesRead < 0) {
            // the key is automatically invalidated once the
            // channel is closed
        	socketChannel.close();
        }
		key.interestOps(SelectionKey.OP_WRITE);
	}

	public static void main(String... args) {
		NIOClient client = new NIOClient("127.0.0.1", 50003);
		client.run();
	}

}
